using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;
using JlPay.Sdk.Core;
using JlPay.Sdk.Models;

namespace JlPay.Sdk.Services
{
    /// <summary>
    /// 服务基类
    /// </summary>
    public abstract class BaseService
    {
        protected readonly Config _config;
        protected readonly IHttpClient _httpClient;
        protected readonly ISignVerifier _signVerifier;
        protected readonly ICryptoService _cryptoService;

        /// <summary>
        /// 创建服务基类
        /// </summary>
        /// <param name="config">配置对象</param>
        protected BaseService(Config config)
        {
            _config = config ?? throw new ArgumentNullException(nameof(config));
            _httpClient = new DefaultHttpClient(config, TimeSpan.FromMilliseconds(config.TimeoutMs), TimeSpan.FromMilliseconds(config.TimeoutMs));
            _signVerifier = new DefaultSignVerifier(config);
            _cryptoService = new DefaultCryptoService(config);
        }

        /// <summary>
        /// 发送POST请求
        /// </summary>
        /// <typeparam name="TRequest">请求类型</typeparam>
        /// <typeparam name="TResponse">响应类型</typeparam>
        /// <param name="request">请求对象</param>
        /// <param name="apiPath">API路径</param>
        /// <returns>响应对象</returns>
        protected async Task<TResponse> PostAsync<TRequest, TResponse>(TRequest request, string apiPath)
            where TResponse : new()
        {
            return await ExecuteAsync<TRequest, TResponse>("POST", request, apiPath);
        }

        /// <summary>
        /// 发送GET请求
        /// </summary>
        /// <typeparam name="TRequest">请求类型</typeparam>
        /// <typeparam name="TResponse">响应类型</typeparam>
        /// <param name="request">请求对象</param>
        /// <param name="apiPath">API路径</param>
        /// <returns>响应对象</returns>
        protected async Task<TResponse> GetAsync<TRequest, TResponse>(TRequest request, string apiPath)
            where TResponse : new()
        {
            return await ExecuteAsync<TRequest, TResponse>("GET", request, apiPath);
        }

        /// <summary>
        /// 执行HTTP请求
        /// </summary>
        /// <typeparam name="TRequest">请求类型</typeparam>
        /// <typeparam name="TResponse">响应类型</typeparam>
        /// <param name="method">HTTP方法</param>
        /// <param name="request">请求对象</param>
        /// <param name="apiPath">API路径</param>
        /// <returns>响应对象</returns>
        protected async Task<TResponse> ExecuteAsync<TRequest, TResponse>(string method, TRequest request, string apiPath)
            where TResponse : new()
        {
            // 构建完整URL
            string url = _config.BaseUrl + apiPath;

            // 获取URI
            string uri = GetUri(apiPath);

            // 将请求对象转换为字典
            var body = ConvertRequestToMap(request);

            // 设置原始请求Map（用于加密）
            if (request is OrgBaseRequest orgBaseRequest)
            {
                orgBaseRequest.SetRawRequestMap(body);
            }

            // 处理请求加密
            var cryptoHeaders = new Dictionary<string, string>();
            HandleEncrypt(request, cryptoHeaders);

            // 签名
            var (sign, timestamp, nonce) = _signVerifier.Sign(method, uri, body);

            // 构建HTTP请求头
            var headers = new Dictionary<string, string>
            {
                ["Content-Type"] = "application/json; charset=utf-8",
                ["x-jlpay-appid"] = _config.AppId, // 使用AppId
                ["x-jlpay-nonce"] = nonce,
                ["x-jlpay-timestamp"] = timestamp,
                ["x-jlpay-sign-alg"] = "SM3WithSM2WithDer",
                ["x-jlpay-sign"] = sign
            };

            // 添加必需的请求头 - 从请求数据中提取商户号和机构号
            if (body.TryGetValue("merch_no", out var merchNo) && merchNo != null)
            {
                headers["x-jlpay-merchno"] = merchNo.ToString()!;
            }
            else if (body.TryGetValue("mch_id", out var mchId) && mchId != null)
            {
                headers["x-jlpay-merchno"] = mchId.ToString()!;
            }
            
            if (body.TryGetValue("org_no", out var orgNo) && orgNo != null)
            {
                headers["x-jlpay-orgno"] = orgNo.ToString()!;
            }

            // 添加加密相关的请求头
            foreach (var kvp in cryptoHeaders)
            {
                headers[kvp.Key] = kvp.Value;
            }

            var httpRequest = new HttpRequest
            {
                Url = url,
                Method = method,
                Headers = headers,
                Body = body
            };

            // 执行请求
            var httpResponse = await _httpClient.ExecuteAsync(httpRequest);

            // 打印响应调试信息
            if (_config.Debug)
            {
                Console.WriteLine($"=== HTTP响应调试信息 ===");
                Console.WriteLine($"状态码: {httpResponse.StatusCode}");
                Console.WriteLine($"响应头数量: {httpResponse.Headers.Count}");
                Console.WriteLine($"响应体长度: {httpResponse.Body?.Length ?? 0}");
                Console.WriteLine($"响应体内容: '{httpResponse.Body}'");
                Console.WriteLine($"=========================");
            }

            // 检查HTTP状态码
            if (httpResponse.StatusCode < 200 || httpResponse.StatusCode >= 300)
            {
                throw new InvalidOperationException($"HTTP请求失败，状态码: {httpResponse.StatusCode}, 响应体: {httpResponse.Body}");
            }

            // 检查响应体是否为空
            if (string.IsNullOrWhiteSpace(httpResponse.Body))
            {
                throw new InvalidOperationException("API返回空响应体，无法解析JSON数据");
            }

            // 验证响应签名
            if (httpResponse.Headers.TryGetValue("x-jlpay-sign", out string? signature))
            {
                try
                {
                    var responseBody = JsonSerializer.Deserialize<Dictionary<string, object>>(httpResponse.Body);
                    if (responseBody != null)
                    {
                        try
                        {
                            _signVerifier.Verify(
                                method,
                                uri,
                                httpResponse.Headers.GetValueOrDefault("x-jlpay-timestamp", ""),
                                httpResponse.Headers.GetValueOrDefault("x-jlpay-nonce", ""),
                                responseBody,
                                signature
                            );
                        }
                        catch (Exception ex)
                        {
                            // 响应签名验证失败时给出警告，但继续处理业务响应
                            if (_config.Debug)
                            {
                                Console.WriteLine($"警告: 响应签名验证失败: {ex.Message}");
                                Console.WriteLine("继续处理业务响应以获取具体错误信息...");
                            }
                            // 不抛出异常，继续处理响应
                        }
                    }
                }
                catch (JsonException ex)
                {
                    if (_config.Debug)
                    {
                        Console.WriteLine($"警告: 响应签名验证时JSON解析失败: {ex.Message}");
                        Console.WriteLine("继续处理业务响应...");
                    }
                }
            }

            // 解析响应
            Dictionary<string, object>? responseData;
            try
            {
                responseData = JsonSerializer.Deserialize<Dictionary<string, object>>(httpResponse.Body);
            }
            catch (JsonException ex)
            {
                // 提供详细的错误信息
                var errorMessage = $"解析API响应JSON失败: {ex.Message}\n" +
                                 $"响应状态码: {httpResponse.StatusCode}\n" +
                                 $"响应体内容: '{httpResponse.Body}'\n" +
                                 $"响应体长度: {httpResponse.Body?.Length ?? 0}";
                
                if (_config.Debug)
                {
                    Console.WriteLine($"=== JSON解析错误详情 ===");
                    Console.WriteLine(errorMessage);
                    Console.WriteLine($"=========================");
                }
                
                throw new InvalidOperationException(errorMessage, ex);
            }
            
            if (responseData == null)
            {
                throw new InvalidOperationException($"解析响应JSON失败，响应体: '{httpResponse.Body}'");
            }

            // 创建响应对象 - 优先使用构造函数解析
            TResponse response;
            if (typeof(TResponse).GetConstructor(new[] { typeof(Dictionary<string, object>) }) != null)
            {
                // 使用带参数的构造函数
                response = (TResponse)Activator.CreateInstance(typeof(TResponse), responseData)!;
            }
            else
            {
                // 使用无参构造函数，然后手动解析
                response = new TResponse();
                ParseResponse(responseData, response);
            }

            // 处理响应解密（在ParseResponse之后进行）
            HandleDecrypt(response, httpResponse.Headers);

            return response;
        }

        /// <summary>
        /// 获取URI路径
        /// </summary>
        /// <param name="apiPath">API路径</param>
        /// <returns>URI路径</returns>
        private static string GetUri(string apiPath)
        {
            if (apiPath.StartsWith("http"))
            {
                var uri = new Uri(apiPath);
                return uri.PathAndQuery;
            }
            return apiPath;
        }

        /// <summary>
        /// 将请求对象转换为字典
        /// </summary>
        /// <param name="request">请求对象</param>
        /// <returns>字典对象</returns>
        private static Dictionary<string, object> ConvertRequestToMap(object request)
        {
            // 优先使用IRawMapGetter接口
            if (request is IRawMapGetter rawMapGetter)
            {
                var (rawMap, exists) = rawMapGetter.GetRawMap();
                if (exists && rawMap.Count > 0)
                {
                    return rawMap;
                }
            }

            // 尝试使用ToMap方法
            if (request is IRequestMapper mapper)
            {
                return mapper.ToMap();
            }

            // 使用JSON序列化转换，使用snake_case命名策略以与敏感字段路径保持一致
            var json = JsonSerializer.Serialize(request, new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
                WriteIndented = false,
                Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
            });

            var result = JsonSerializer.Deserialize<Dictionary<string, object>>(json, new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
            });
            return result ?? new Dictionary<string, object>();
        }

        /// <summary>
        /// 处理请求加密
        /// </summary>
        /// <param name="request">请求对象</param>
        /// <param name="headers">请求头</param>
        private void HandleEncrypt(object? request, Dictionary<string, string> headers)
        {
            if (request == null)
            {
                return;
            }
            
            var cryptoHeaders = _cryptoService.EncryptRequest(request);
            foreach (var kvp in cryptoHeaders)
            {
                headers[kvp.Key] = kvp.Value;
            }
        }

        /// <summary>
        /// 处理响应解密
        /// </summary>
        /// <param name="response">响应对象</param>
        /// <param name="headers">响应头</param>
        private void HandleDecrypt(object response, Dictionary<string, string> headers)
        {
            _cryptoService.DecryptResponse(response, headers);
        }

        /// <summary>
        /// 解析响应数据到响应对象
        /// </summary>
        /// <param name="responseData">响应数据</param>
        /// <param name="response">响应对象</param>
        private static void ParseResponse(Dictionary<string, object> responseData, object response)
        {
            var properties = response.GetType().GetProperties();
            
            foreach (var prop in properties)
            {
                if (prop.CanWrite)
                {
                    // 尝试多种可能的键名，优先尝试snake_case格式
                    var possibleKeys = new[]
                    {
                        PascalToSnakeCase(prop.Name), // snake_case (如 SettleType -> settle_type)
                        prop.Name.ToLower(), // 全小写
                        prop.Name.ToLowerInvariant(), // 全小写（不变文化）
                        prop.Name.ToUpper(), // 全大写
                        prop.Name, // 原始名称
                        SnakeToPascalCase(prop.Name) // 从snake_case转换
                    };

                    foreach (var key in possibleKeys)
                    {
                        if (responseData.TryGetValue(key, out var value))
                        {
                            try
                            {
                                // 如果属性类型是string，直接转换
                                if (prop.PropertyType == typeof(string))
                                {
                                    prop.SetValue(response, value?.ToString());
                                }
                                // 如果属性类型是bool，转换bool值
                                else if (prop.PropertyType == typeof(bool))
                                {
                                    if (value is bool boolValue)
                                        prop.SetValue(response, boolValue);
                                    else if (value is string stringValue)
                                        prop.SetValue(response, bool.Parse(stringValue));
                                }
                                // 如果属性类型是可空类型
                                else if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                                {
                                    var underlyingType = Nullable.GetUnderlyingType(prop.PropertyType);
                                    if (underlyingType == typeof(string))
                                    {
                                        prop.SetValue(response, value?.ToString());
                                    }
                                    else if (underlyingType == typeof(bool))
                                    {
                                        if (value is bool boolValue)
                                            prop.SetValue(response, boolValue);
                                        else if (value is string stringValue)
                                            prop.SetValue(response, bool.Parse(stringValue));
                                    }
                                    else if (underlyingType == typeof(int))
                                    {
                                        if (value is int intValue)
                                            prop.SetValue(response, intValue);
                                        else if (value is long longValue)
                                            prop.SetValue(response, (int)longValue);
                                        else if (value is string stringValue && int.TryParse(stringValue, out int parsedInt))
                                            prop.SetValue(response, parsedInt);
                                        else if (value != null)
                                            prop.SetValue(response, Convert.ToInt32(value));
                                    }
                                    else if (underlyingType == typeof(long))
                                    {
                                        if (value is long longValue)
                                            prop.SetValue(response, longValue);
                                        else if (value is int intValue)
                                            prop.SetValue(response, (long)intValue);
                                        else if (value is string stringValue && long.TryParse(stringValue, out long parsedLong))
                                            prop.SetValue(response, parsedLong);
                                        else if (value != null)
                                            prop.SetValue(response, Convert.ToInt64(value));
                                    }
                                    else if (underlyingType == typeof(decimal))
                                    {
                                        if (value is decimal decimalValue)
                                            prop.SetValue(response, decimalValue);
                                        else if (value is string stringValue && decimal.TryParse(stringValue, out decimal parsedDecimal))
                                            prop.SetValue(response, parsedDecimal);
                                        else if (value != null)
                                            prop.SetValue(response, Convert.ToDecimal(value));
                                    }
                                }
                                else
                                {
                                    // 尝试直接转换
                                    prop.SetValue(response, Convert.ChangeType(value, prop.PropertyType));
                                }
                                break; // 找到并设置了值，跳出内层循环
                            }
                            catch
                            {
                                // 转换失败，继续尝试下一个键
                                continue;
                            }
                        }
                    }
                }
            }

            // 处理复杂字段 - 确保在所有基本字段处理完成后调用
            if (response is IComplexFieldHandler complexHandler)
            {
                foreach (var kvp in responseData)
                {
                    complexHandler.HandleComplexField(kvp.Key, kvp.Value);
                }
            }
        }

        /// <summary>
        /// PascalCase转snake_case
        /// </summary>
        /// <param name="pascalCase">PascalCase字符串</param>
        /// <returns>snake_case字符串</returns>
        private static string PascalToSnakeCase(string pascalCase)
        {
            if (string.IsNullOrEmpty(pascalCase))
                return pascalCase;
            
            var result = "";
            for (int i = 0; i < pascalCase.Length; i++)
            {
                if (i > 0 && char.IsUpper(pascalCase[i]))
                {
                    result += "_";
                }
                result += char.ToLower(pascalCase[i]);
            }
            return result;
        }

        /// <summary>
        /// snake_case转PascalCase
        /// </summary>
        /// <param name="snakeCase">snake_case字符串</param>
        /// <returns>PascalCase字符串</returns>
        private static string SnakeToPascalCase(string snakeCase)
        {
            if (string.IsNullOrEmpty(snakeCase))
                return snakeCase;
            
            var result = "";
            var nextUpper = true;
            
            for (int i = 0; i < snakeCase.Length; i++)
            {
                if (snakeCase[i] == '_')
                {
                    nextUpper = true;
                }
                else
                {
                    if (nextUpper)
                    {
                        result += char.ToUpper(snakeCase[i]);
                        nextUpper = false;
                    }
                    else
                    {
                        result += char.ToLower(snakeCase[i]);
                    }
                }
            }
            return result;
        }
    }

    /// <summary>
    /// 复杂字段处理接口
    /// </summary>
    public interface IComplexFieldHandler
    {
        /// <summary>
        /// 处理复杂字段
        /// </summary>
        /// <param name="fieldName">字段名</param>
        /// <param name="fieldValue">字段值</param>
        void HandleComplexField(string fieldName, object fieldValue);
    }
} 